﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Reflection;


namespace HasuSLLib.Utility
{
    public static  class SLExtensions
    {
        public static T  HasuSLClone<T>(this  Object source)
        {

            /* if (!typeof(T).IsSerializable)
            {
            throw new ArgumentException("The type must be serializable.", "source");
            }*/

            // Don't serialize a null object, simply return the default for that object
            if (Object.ReferenceEquals(source, null))
            {
                return default(T);
            }
            if (typeof(T).FullName != source.GetType().FullName)
            {
                throw new ArgumentException("The type must be serializable.", "source");
            }

            #region XmlSerializer old code
            /*
            XmlSerializer serializer = new XmlSerializer(source.GetType());
            using (Stream stream = new MemoryStream())
            {
                serializer.Serialize(stream, source);
                stream.Seek(0, SeekOrigin.Begin);
                return (T)serializer.Deserialize(stream);
            } 
             */
            #endregion

            T cloned = (T)Activator.CreateInstance(source.GetType());

            clone(source, cloned);
            return cloned;
        }

        public static void clone(Object source, Object target)
        {
            if (Object.ReferenceEquals(source, null) || Object.ReferenceEquals(target, null))
            {
                return ;
            }
            if (target.GetType().FullName != source.GetType().FullName)
            {
                throw new ArgumentException("The type must be serializable.", "source");
            }

            List<MemberInfo> fields = new List<MemberInfo>(  source.GetType().GetMembers(BindingFlags.GetField | BindingFlags.Public));

            List<PropertyInfo> properties = new List<PropertyInfo>( source.GetType().GetProperties());
            properties.ForEach( propertie => 
                {
                    if (propertie.PropertyType.IsClass && propertie.PropertyType != typeof(string) )
                    {
                        object srcVal = propertie.GetValue(source, null);
                        if (srcVal == null)
                        {
                            return;
                        }
                        object trgVal = propertie.GetValue(target, null);
                        if (trgVal == null && srcVal !=null )
                        {
                            trgVal = Activator.CreateInstance(propertie.PropertyType);
                        }
                        clone(srcVal, trgVal);
                    }
                    else
                    {
                        CopyValue(source, target, propertie);
                    }
                });
        }

        private static void CopyValue(Object source, Object target, PropertyInfo propertie)
        {
            propertie.SetValue(target, propertie.GetValue(source, null), null);
        }

    }
}
